package framework.grid.data;


import java.io.Serializable;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.TreeMap;

import framework.fault.IFaultTolerantPeer;


public class ReplicatedNodeData implements INodeData, Serializable {

	private HashSet<IRemoteNodeData> replicas;

	public static ReplicatedNodeData createInstance(IFaultTolerantPeer[] peers) throws RemoteException {
		HashSet<IRemoteNodeData> replicas = new HashSet<IRemoteNodeData>();
		for (int i=0; i<peers.length; i++) {
			replicas.add(peers[i].createRemoteNodeData());
		}
		return new ReplicatedNodeData(replicas);
	}
	
	//TODO possible optimization: dont create new replicas if they already exist remotely
	public static ReplicatedNodeData copyInstance(ReplicatedNodeData oldData, IFaultTolerantPeer[] peers) 
	throws RemoteException {
		HashSet<IRemoteNodeData> replicas = new HashSet<IRemoteNodeData>();
		for (int i=0; i<peers.length; i++) {
			IRemoteNodeData replica = peers[i].createRemoteNodeData();
			replica.setValues(oldData.getValues());
			replicas.add(replica);
		}
		return new ReplicatedNodeData(replicas);
	}
	
	private ReplicatedNodeData(HashSet<IRemoteNodeData> replicas) {
		this.replicas = replicas;
	}
	
	@Override
	public String[] get(String key) throws RemoteException {
		for (IRemoteNodeData data: replicas) {
			try {
				return data.get(key);
			} catch (RemoteException e) {
				//Some of the remote data's peer is offline
			}
		}
		return null;
	}

	@Override
	public void put(String key, String value) throws RemoteException {
		for (IRemoteNodeData data: replicas) {
			try {
				data.put(key, value);
			} catch (RemoteException e) {
				//Some of the remote data's peer is offline
			}
		}
	}

	@Override
	public String[] remove(String key) throws RemoteException {
		String[] out = null;
		for (IRemoteNodeData data: replicas) {
			try {
				String[] temp = data.remove(key);
				if (out==null && temp!=null) {
					out = temp;
				}
			} catch (RemoteException e) {
				//Some of the remote data's peer is offline
			}
		}
		return out;
	}

	@Override
	public void setValues(TreeMap<String, ArrayList<String>> values)
			throws RemoteException {
		for (IRemoteNodeData data: replicas) {
			try {
				data.setValues(values);
			} catch (RemoteException e) {
				//Some of the remote data's peer is offline
			}
		}
	}

	@Override
	public TreeMap<String, ArrayList<String>> getValues()
			throws RemoteException {
		for (IRemoteNodeData data: replicas) {
			try {
				return data.getValues();
			} catch (RemoteException e) {
				//Some of the remote data's peer is offline
			}
		}
		return null;
	}

}
